package com.hup.sokoban.view.mapDesigner;

import com.hup.sokoban.model.common.MapItem;
import com.hup.sokoban.mvp.MapDesignerMvp.MapDesignerPresenter;
import com.hup.sokoban.service.common.PlayerKeyService;
import com.hup.sokoban.service.common.PlayerKeyService.PlayerKeyHandler;
import com.hup.sokoban.service.mapDesigner.MapLabelDrawingGesture;
import com.hup.sokoban.view.customView.MapLabel;
import com.hup.sokoban.view.customView.StepRecordPanel;
import com.hup.sokoban.view.customView.mapListView.MapListView.MenuListener;
import com.hup.sokoban.view.main.MainFrame;
import com.hup.utils.commons.TextUtil;
import com.hup.utils.commons.hardware.ScreenUtil;
import com.hup.utils.commons.hardware.SystemUtil;
import com.hup.utils.commons.start.DialogHelper;
import com.hup.utils.commons.start.SpringContext;
import com.hup.utils.swing.frame.BaseFrame;
import com.hup.utils.swing.frame.HelpDialog;
import com.hup.utils.swing.model.BaseWindowConfig;
import lombok.extern.log4j.Log4j2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;

/**
 * @author hugan
 * @date 2020/4/29
 */
@Log4j2
public class MapDesignerFrame extends BaseFrame {

    private MapDesignerForm form;
    private final MapDesignerPresenter presenter;
    /**
     * 当前被绘制的map
     * 与关卡列表model中的元素是不等的!:避免用户绘制地图时,列表页跟着刷新
     */
    private MapItem curMap;
    /**
     * 上次[加载/新建/保存]的map
     */
    private MapItem lastLoadedMap;
    private MainFrame formWindow;

    public static void showFrame(MainFrame formWindow, BaseWindowConfig windowConfig) {
        MapDesignerFrame frame = new MapDesignerFrame();
        frame.formWindow = formWindow;
        windowConfig.initFrame(frame);
        formWindow.setVisible(false);
        frame.setVisible(true);
    }

    private MapDesignerFrame() {
        super("关卡设计器");
        presenter = SpringContext.getBean(MapDesignerPresenter.class);

        initView();
        initListener();

        execute("加载关卡列表", presenter::reloadMapList, mapItems -> {
            form.mapListView.setMapItems(mapItems);
            form.mapListView.setSelectedIndex(mapItems.size() - 1);
            newDefaultMap(form.mapListView.getMapCount());
        });
    }

    private void initView() {
        form = new MapDesignerForm();
        setContentPane(form.root);
        form.txtBackgroundImage.setExts(new String[]{
                "gif", "jpg", "jpeg", "png", "bmp"});

        Rectangle usableBounds = ScreenUtil.getScreenUsableBounds();
        log.debug("usableBounds={}", usableBounds);
        setSize(usableBounds.width / 2, usableBounds.height / 2);
        setLocationRelativeTo(null);

        handleLeftPanelVisible(true);

        SystemUtil.disableInputMethods(this, true);
        SystemUtil.enableInputMethods(form.txtMapName, false);
        SystemUtil.enableInputMethods(form.txtDescription, false);
    }

    private void initListener() {
        initLeftListener();
        initBottomListener();

        MapLabelDrawingGesture.bind(form.mapLabel, () -> form.mapElementPanel.getElementType());
        PlayerKeyService.bind(new PlayerKeyHandler() {
            @Override
            public MapLabel getMapLabel() {
                return form.mapLabel;
            }

            @Override
            public StepRecordPanel getStepRecordPanel() {
                return form.stepRecordPanel;
            }

            @Override
            public void onWinning() {
                //do nothing
                log.debug("");
            }
        });
    }

    private void initLeftListener() {
        form.mapListView.setMenuListener(new MenuListener() {
            @Override
            public boolean beforeLoadItem(MapItem mapItem) {
                showMapInfoPanel();
                updateMapByUi();
                boolean canLoad = true;
                if (!presenter.isSame(curMap, lastLoadedMap)) {
                    canLoad = DialogHelper.yesNo("是否丢弃已修改的内容?").title("加载").show(MapDesignerFrame.this);
                }
                log.info("canLoad={}", canLoad);
                if (canLoad) {
                    curMap = mapItem.getClone();
                    lastLoadedMap = mapItem.getClone();
                    updateUiByMap();
                }
                return canLoad;
            }

            @Override
            public void useMapData(MapItem mapItem) {
                boolean ok = DialogHelper.yesNo("确认覆盖当前地图?").show(MapDesignerFrame.this);
                if (ok) {
                    presenter.copyMapData(curMap, mapItem);
                    updateUiByMap();
                }
            }

            @Override
            public boolean beforeDeleteItem(MapItem mapItem) {
                //删除时,不需要校验有无保存修改
                String msg;
                boolean deleteCur = false;
                if (mapItem.getPath().equals(curMap.getPath())) {
                    msg = "确认删除当前关卡[" + mapItem.getName() + "]?";
                    deleteCur = true;
                } else {
                    msg = "确认删除[" + mapItem.getName() + "]?";
                }
                boolean delete = DialogHelper.yesNo(msg).show(MapDesignerFrame.this);
                log.info("delete={}", delete);
                if (delete) {
                    presenter.doDelete(mapItem);
                    if (deleteCur) {
                        newDefaultMap(form.mapListView.getMapCount() - 1);
                    }
                }
                return delete;
            }
        });

        form.txtBackgroundImage.setChoseListener(chosePath -> {
            curMap.setBackgroundImage(chosePath);
            form.mapLabel.notifyDataUpdated();
        });
        form.cbLockBgScale.addActionListener(e -> {
            curMap.setLockBgScale(form.cbLockBgScale.isSelected());
            form.mapLabel.notifyDataUpdated();
        });
    }

    private void initBottomListener() {
        form.cbMapList.addActionListener(e -> handleLeftPanelVisible(true));
        form.cbMapList.registerKeyboardAction(e -> ((AbstractButton) e.getSource()).doClick(),
                KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
        form.cbMapInfo.addActionListener(e -> handleLeftPanelVisible(false));
        form.cbMapInfo.registerKeyboardAction(e -> ((AbstractButton) e.getSource()).doClick(),
                KeyStroke.getKeyStroke(KeyEvent.VK_C, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);

        form.btnNew.addActionListener(e -> {
            showMapInfoPanel();
            updateMapByUi();
            boolean isNew = true;
            if (!presenter.isSame(curMap, lastLoadedMap)) {
                isNew = DialogHelper.yesNo("是否丢弃已修改的内容?").title("新建").show(this);
            }
            if (isNew) {
                newDefaultMap(form.mapListView.getMapCount());
            }
        });
        form.btnSave.addActionListener(e -> {
            showMapInfoPanel();
            updateMapByUi();
            curMap.updateMapSafeFields();
            curMap.refreshRecordsState();
            form.mapLabel.notifyDataUpdated();//刷新界面

            boolean needDelete = presenter.needDeleteMapRecords(curMap, lastLoadedMap);
            if (needDelete) {
                boolean ok = DialogHelper.yesNo("地图元素已修改,将会删除该关卡的游戏记录,确认继续?").show(this);
                if (!ok) return;
            }
            execute("保存", () -> {
                presenter.checkAndSaveMap(curMap, lastLoadedMap);
                lastLoadedMap = curMap.getClone();
                //重新加载列表
                return presenter.reloadMapList();
            }, mapItems -> {
                form.mapListView.setMapItems(mapItems);
                updateUiByMap();
            });
        });

        form.mapBoundsPanel.setMapLabel(form.mapLabel);
        form.btnHelp.setActionListener(e -> HelpDialog.builder().model(false).doShow(this, "MapDesignerFrame"));
    }

    /**
     * 展开[关卡信息]
     */
    private void showMapInfoPanel() {
        form.cbMapInfo.setSelected(true);
        handleLeftPanelVisible(false);
    }

    private void newDefaultMap(int mapListSize) {
        log.info("新建省缺map");
        curMap = MapItem.getDefault();
        curMap.setName("关卡" + (mapListSize + 1));
        lastLoadedMap = curMap.getClone();
        updateUiByMap();
    }

    private void handleLeftPanelVisible(boolean clickCbMapList) {
        boolean showList = form.cbMapList.isSelected();
        boolean showInfo = form.cbMapInfo.isSelected();
        if ((clickCbMapList && !showList) || (!showList && !showInfo)) {
            //都不选中,隐藏整个面板
            form.pLeft.setVisible(false);
            form.cbMapInfo.setSelected(false);
            return;
        }
        //至少选中一个,肯定显示[关卡列表](并选中复选框)
        form.cbMapList.setSelected(true);
        form.mapListView.setVisible(true);
        form.pMapInfo.setVisible(showInfo);
        form.pLeft.setVisible(true);
    }

    private void updateUiByMap() {
        setSubTitle(curMap.getName());
        form.mapListView.setSelectedItem(curMap);
        form.mapLabel.setData(curMap);

        form.txtMapName.setText(curMap.getName());
        form.txtDescription.setText(curMap.getDescription());
        form.txtBackgroundImage.setSelectedFilePath(curMap.getBackgroundImage());
        form.cbLockBgScale.setSelected(curMap.isLockBgScale());
        form.stepRecordPanel.reset();
    }

    private void updateMapByUi() {
        curMap.setName(TextUtil.nullAtEmpty(form.txtMapName.getText()));
        curMap.setDescription(TextUtil.nullAtEmpty(form.txtDescription.getText()));
        curMap.setBackgroundImage(form.txtBackgroundImage.getSelectedFilePath());
        curMap.setLockBgScale(form.cbLockBgScale.isSelected());
    }


    @Override
    public boolean onWindowClosing(WindowEvent e) {
        boolean close = true;
        updateMapByUi();
        if (!presenter.isSame(curMap, lastLoadedMap)) {
            close = DialogHelper.yesNo("是否丢弃已修改的内容?").title("新建").show(this);
        }
        return close;
    }

    @Override
    public void onHidden(boolean dispose) {
        log.info("dispose={}", dispose);
        form.mapListView.clearMapItems();
        if (formWindow != null) {
            formWindow.setVisible(true);
            formWindow = null;
        } else {
            System.exit(0);//开发测试
        }
    }

}
